﻿using Mina.Core.Buffer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HttpPerfLoad
{
    class RequestManager
    {
        public int numRequests;
        List<Pair> sessionList;
        string requestData;
        int requestInterval;
        public event EventHandler AllThreadsRunToCompleted;
        public RequestManager(List<Pair> pairList, int numRequests, string requestData, int requestInterval)
        {
            this.requestInterval = requestInterval;
            this.requestData = requestData;
            this.numRequests = numRequests;
            this.sessionList = pairList;
        }

        public static long numThread;
        private bool stopRequested;
        public void Start()
        {
            new Thread(threadMain).Start();
        }
        public void Stop()
        {
            this.stopRequested = true;
        }

        private void threadMain()
        {
            var numSessionPerThread = (int)Math.Floor(sessionList.Count / (decimal)numRequests * 2);
            if (numRequests == 1)
            {
                numSessionPerThread = 1;
            }
            for (int i = 0; i < numRequests; i++)
            {
                if (stopRequested)
                    break;
                var batchList = sessionList.Skip(i * numSessionPerThread).Take(numSessionPerThread * 2).ToList();
                if (!batchList.Any())
                    break;
                new Thread(ThreadWork) { IsBackground = true }.Start(batchList);
                //if (!ThreadPool.QueueUserWorkItem(ThreadWork, batchList))
                //{
                //    Console.WriteLine("quene work failed");
                //}
                Thread.Sleep(120);
            }
        }

        void ThreadWork(object state)
        {
            Interlocked.Increment(ref numThread);
            var pairList = state as List<Pair>;
            while (pairList.Any() && !stopRequested)
            {
                List<Pair> removeList = new List<Pair>();

                foreach (var pair in pairList)
                {
                    if (stopRequested)
                        break;
                    try
                    {
                        if (!pair.SessionBroken)
                        {
                            var requestBytes = Encoding.UTF8.GetBytes(requestData);
                            pair.Session.Write(IoBuffer.Wrap(requestBytes));
                            if (pairList.Count != 1 && pairList.IndexOf(pair) % 2 == 0)
                            {
                                continue;
                            }
                            Thread.Sleep(TimeSpan.FromMilliseconds(this.requestInterval));
                            //if (!pair.SessionBroken)
                            //{
                            //    continue;
                            //}
                        }
                    }
                    catch (Exception ex)
                    {
                        pair.SessionBroken = true;
                        removeList.Add(pair);
                    }
                }
                foreach (var pair in removeList)
                {
                    if (pair.SessionBroken && pair.Session != null)
                    {
                        lock (pairList)
                        {
                            pair.Session.Close(true);
                            pair.connector.Dispose();
                            pairList.Remove(pair);
                        }
                    }
                }
            }
            Interlocked.Decrement(ref numThread);
            if (AllThreadsRunToCompleted != null && Interlocked.Read(ref numThread) == 0)
            {
                AllThreadsRunToCompleted.Invoke(this, EventArgs.Empty);
            }
        }
    }
}
